package cn.xuqiudong.backend.config.satoken;

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.fun.SaParamFunction;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.xuqiudong.backend.base.auth.SaTokenAuthHelper;
import cn.xuqiudong.backend.base.auth.user.BaseUserInfo;
import cn.xuqiudong.backend.base.auth.user.UserInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 描述:
 * sa-token config
 *
 * @author Vic.xu
 * @since 2025-02-05 17:20
 */
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {


    private UserInfoService userInfoService;

    @Autowired(required = false)
    public void setUserInfoService(UserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }


    /**
     * sa token拦截器配置，
     * 不是直接StpUtil.checkLogin(); 而是
     * 如果 Token 过期（8 小时后），但 RememberMe（7 天）仍然有效 → 自动登录
     * 如果 RememberMe 也失效了（7 天后）→ 抛出 NotLoginException，前端引导用户重新登录
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        SaParamFunction saParamFunction = handler -> {
            // 1. 已登录，直接放行
             if (StpUtil.isLogin()) {
                return;
            }
            // 2. 获取 token
            String tokenValue = StpUtil.getTokenValue();
            if (StringUtils.isNotBlank(tokenValue)) {
                Object loginId = StpUtil.getLoginIdByToken(tokenValue);
                if (loginId != null && userInfoService != null) {
                    // 3. 查询用户信息
                    BaseUserInfo userInfo = userInfoService.getUserInfo((String) loginId);
                    if (userInfo != null) {
                        // 4. 恢复 Session
                        StpUtil.getSessionByLoginId(userInfo.getId(), true);

                        // 5. 以相同 Token 续期
                        SaLoginParameter loginModel = new SaLoginParameter()
                                // 继续使用当前 Token
                                .setToken(tokenValue)
                                //   保持记住我状态
                                .setIsLastingCookie(true)
                                // 更新超时时间
                                .setTimeout(SaManager.getConfig().getTimeout())
                                // 自定义标记，表示是 Token 续期
                                .setExtra("renew", true);
                        StpUtil.login(userInfo.getId(), loginModel);
                        SaTokenAuthHelper.setUserInfo(userInfo);
                        return;
                    }
                }
            }
            // 6. 抛出异常 让 SaInterceptor 返回 401
            SaResponse response = SaHolder.getResponse();
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setHeader("Content-Type", "application/json;charset=UTF-8");
            throw new BackResultException("Token 过期，请重新登录");
        };
        SaInterceptor saInterceptor = new SaInterceptor(saParamFunction);

        registry.addInterceptor(saInterceptor)
                // 拦截所有请求
                .addPathPatterns("/**")
                // 排除登录、登出接口
                .excludePathPatterns("/test/**",
                        "/main/login",
                        "/main/logout",
                        "/main/test",

                        "/swagger-ui.html",
                        "/swagger-ui/index.html",
                        "/v3/api-docs/**",
                        // common  exclude path
                        "/error/**",
                        "/generator/**",
                        "/generator.html",
                        "/static/**",
                        "/resources/**",
                        "/public/**",
                        "/webjars/**",
                        "/css/**",
                        "/js/**",
                        "/**/*.js",
                        "/**/*.css",
                        "/favicon.ico",
                        "/images/**"
                );


    }
}
